package com.wzdigit.wms.wms.task.order;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wzdigit.wms.basic.client.request.transfer.ConfirmInvZoneItemRequest;
import com.wzdigit.wms.basic.client.request.transfer.SearchInvRequest;
import com.wzdigit.wms.basic.client.response.transfer.AvailableInvZoneByWhsResponse;
import com.wzdigit.wms.basic.client.response.transfer.AvailableInvZoneGroupWhsResponse;
import com.wzdigit.wms.basic.domain.dtos.transfer.GdnUnPickGroupWhsDto;
import com.wzdigit.wms.basic.domain.inventory.Lotno;
import com.wzdigit.wms.basic.domain.transfer.CtnrLoading;
import com.wzdigit.wms.basic.domain.transfer.GdnDtl;
import com.wzdigit.wms.basic.domain.transfer.GdnHeader;
import com.wzdigit.wms.basic.enums.CtnrLoadingStatusEnum;
import com.wzdigit.wms.basic.enums.GdnDtlArrangeCtnrFlagEnum;
import com.wzdigit.wms.basic.enums.GdnDtlUdf1Enum;
import com.wzdigit.wms.basic.enums.WarehouseEnum;
import com.wzdigit.wms.basic.mapper.core.transfer.CtnrLoadingMapper;
import com.wzdigit.wms.basic.mapper.core.transfer.GdnDtlMapper;
import com.wzdigit.wms.basic.mapper.core.transfer.GdnHeaderMapper;
import com.wzdigit.wms.basic.mapper.core.transfer.InvZoneMapper;
import com.wzdigit.wms.basic.util.StringUtils;
import com.wzdigit.wms.basic.util.common.LockNumber;
import com.wzdigit.wms.basic.util.common.LockString;
import com.wzdigit.wms.basic.service.code.LotnoService;
import com.wzdigit.wms.basic.service.code.RedisService;
import com.wzdigit.wms.wms.service.outbound.PicktaskService;
import com.wzdigit.wms.wms.service.transfer.GdnService;
import lombok.extern.slf4j.Slf4j;
import net.dreamlu.mica.core.utils.BeanUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 发货单相关调度任务的业务逻辑 服务类
 * 
 * @author Administrator
 *
 */
@Service
@Slf4j
public class GdnScheduleDealService {
	
	@Autowired
	private CtnrLoadingMapper ctnrLoadingMapper;
	
	@Autowired
	private GdnHeaderMapper gdnHeaderMapper;
	
	@Autowired
	private InvZoneMapper invZoneMapper;
	
	@Autowired
	private GdnDtlMapper gdnDtlMapper;
	
	@Autowired
    private LotnoService lotnoService;
	
	@Autowired
    private GdnService gdnService;
	
	@Autowired
    private RedisService redisService;
	
	@Autowired
	private PicktaskService picktaskService;
	
	private final static String GDN_DTL_LOCK = LockString.WMS_GDN_DTL_LOCK_KEY;
	
	private final static String AUTO_TEXT = "系统自动分库";
	
	/**
	 * 发货单自动分配仓库--分配库存操作
	 * @throws Exception 
	 * @throws  
	 */
	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
	public void allowAlocDeal(String taskName, String loginName, Date date, BigDecimal zero,
			GdnDtl gdnDtl, Map<Long, GdnHeader> gdnHeaderMap) throws Exception {
		String lockKeyStr = GDN_DTL_LOCK + gdnDtl.getGdnDtlId();
		if (redisService.lock(lockKeyStr, LockNumber.SECONDS_II)) {
			try {
				log.info(taskName + "锁锁定：" + lockKeyStr);
				
				// 发货单表头
				GdnHeader gdnHeader = gdnHeaderMap.get(gdnDtl.getGdnHeaderId());
				if (gdnHeader == null) {
					gdnHeader = gdnHeaderMapper.selectById(gdnDtl.getGdnHeaderId());
					gdnHeaderMap.put(gdnDtl.getGdnHeaderId(), gdnHeader);
				}

				// 找批次号
				String lotnoStr = gdnDtl.getLotno();
				if(StringUtils.isNull(lotnoStr)) {
					Lotno lotno = lotnoService.getLotnoByGdnDtlId(gdnDtl.getGdnDtlId());
					if(lotno == null) {
						return; // 跳出，执行下一个循环
					}
					lotnoStr = lotno.getLotno();
				}
				
				// 查找可用库存
				SearchInvRequest dto = new SearchInvRequest();
				dto.setLotno(lotnoStr);
				dto.setSkuId(gdnDtl.getSkuId());
				dto.setWhsId(gdnDtl.getWhsId());
				dto.setVendorId(gdnDtl.getVendor());
				dto.setInvAttr(gdnDtl.getInvAttr());
				dto.setQaStatus(gdnDtl.getQaStatus());
				dto.setFactory(gdnHeader.getFactory());
				List<AvailableInvZoneGroupWhsResponse> availableInvZoneGroupWhs = invZoneMapper.
						getAvailableInvZoneGroupWhs(dto, null, WarehouseEnum.availableInvWhsTypeListAuto);
				if (availableInvZoneGroupWhs.size() == 0) {
					return; // 跳出，执行下一个循环
				}
				
				List<Integer> gdnWhsIdList = availableInvZoneGroupWhs.stream().map(AvailableInvZoneGroupWhsResponse::getWhsId).distinct().collect(Collectors.toList());
	        	List<GdnUnPickGroupWhsDto> unPickGroupWhsList = gdnDtlMapper.selectUnPickGroupWhs(gdnDtl.getSkuId(), lotnoStr, gdnWhsIdList);
		        Map<Integer, GdnUnPickGroupWhsDto> unPickGroupWhsMap = unPickGroupWhsList.stream().collect(Collectors.toMap(GdnUnPickGroupWhsDto::getWhsId, gdnUnPickGroupWhsDto -> gdnUnPickGroupWhsDto));
		        for (AvailableInvZoneGroupWhsResponse one : availableInvZoneGroupWhs) {
        			GdnUnPickGroupWhsDto gdnUnPickGroupWhsDto = unPickGroupWhsMap.get(one.getWhsId());
        			if(gdnUnPickGroupWhsDto != null) {
        				BigDecimal unPickQty = gdnUnPickGroupWhsDto.getOrderQty().subtract(gdnUnPickGroupWhsDto.getPickQty());
        				one.setAvailableQty(one.getAvailableQty().subtract(unPickQty));
        			}
				}
		        // 过滤掉可用库存小于等于0的
		        availableInvZoneGroupWhs = availableInvZoneGroupWhs.stream().filter(a -> a.getAvailableQty().signum() == 1).collect(Collectors.toList());
				if (availableInvZoneGroupWhs.size() == 0) {
					return; // 跳出，执行下一个循环
				}

				// 剩下未分配数量
				BigDecimal remainOrderQty = gdnDtl.getOrderQty();

				// 分配库存入参集合
				List<ConfirmInvZoneItemRequest> items = new ArrayList<ConfirmInvZoneItemRequest>();
				for (AvailableInvZoneGroupWhsResponse one : availableInvZoneGroupWhs) {
					ConfirmInvZoneItemRequest item = new ConfirmInvZoneItemRequest();
					item.setWhsId(one.getWhsId());
					item.setWhsCode(one.getWhsCode());
					item.setWhsName(one.getWhsName());

					// 每个仓库的可用库存
					BigDecimal availableQty = one.getAvailableQty();
					if (remainOrderQty.compareTo(availableQty) <= 0) {
						// 需求数量 <= 可用库存
						item.setQty(remainOrderQty);
						remainOrderQty = zero;
					} else {
						// 需求数量 > 可用库存
						item.setQty(availableQty);
						remainOrderQty = remainOrderQty.subtract(availableQty);
					}
					items.add(item);
					
					// 全部数量分配完毕
					if (remainOrderQty.signum() == 0) {
						break;
					}
				}
				
				// 没有全部分完
				if (remainOrderQty.signum() == 1) {
					return; // 跳出
				}

				// 排柜单信息
				CtnrLoading ctnrLoading = null;
				if (gdnHeader.getCntrNo() != null || gdnHeader.getSealNo() != null
						|| gdnHeader.getBookingNo() != null || gdnHeader.getVehicleNo() != null) {
					ctnrLoading = new CtnrLoading();
					ctnrLoading.setGdnNo(gdnHeader.getGdnNo());
					ctnrLoading.setCntrNo(gdnHeader.getCntrNo());
					ctnrLoading.setSealNo(gdnHeader.getSealNo());
					ctnrLoading.setCntrType(gdnHeader.getCntrType());
					ctnrLoading.setBookingNo(gdnHeader.getBookingNo());
					ctnrLoading.setVehicleNo(gdnHeader.getVehicleNo());

					ctnrLoading.setCreateTime(date);
					ctnrLoading.setCreateUser(loginName);
					ctnrLoading.setCmpQty(zero);
					ctnrLoading.setStatus(CtnrLoadingStatusEnum.CREATE.code);

					ctnrLoading.setCntrSeq(gdnHeader.getCntrSeq());
					ctnrLoading.setCarrier(gdnHeader.getCarrierId());
					ctnrLoading.setRefCntrNo(gdnHeader.getRefCntrNo());
					ctnrLoading.setRefCntrType(gdnHeader.getCntrType());
					ctnrLoading.setDockOfLoading(gdnHeader.getShipPort()); // 装柜码头
					ctnrLoading.setPlanLoadingTime(gdnHeader.getPlanLoadingTime());
				}

				// 锁住最大行号
				Integer lockMaxGdnLineNo = 0;
				if (items.size() > 0) {
					lockMaxGdnLineNo = gdnDtlMapper.lockMaxGdnLineNo(gdnHeader.getGdnHeaderId());
				}

				// 仓库预配数量
				int whsPreAlocQty;
				// 库区预配数量
				int zonePreAlocQty;
				// 仓库的可用数量
				int whsAvailableQty;
				// 库区的可用数量
				int zoneAvailableQty;

				// 遍历每个仓库分配多少数量
				int i = 0;

				for (ConfirmInvZoneItemRequest item : items) {
					// 传入各自仓库ID
					dto.setWhsId(item.getWhsId());

					// 校验仓库的可用库存是否足够
					whsAvailableQty = 0;
					List<AvailableInvZoneByWhsResponse> availableInvZone = invZoneMapper.getAvailableInvZoneByWhs(dto);
					for (AvailableInvZoneByWhsResponse invZone : availableInvZone) {
						whsAvailableQty += invZone.getAvailableQty().intValue();
					}
					// 扣去未拣货的数量
					GdnUnPickGroupWhsDto unPickDto = unPickGroupWhsMap.get(item.getWhsId());
					if(unPickDto != null) {
						int unPickQty = (unPickDto.getOrderQty().subtract(unPickDto.getPickQty())).intValue();
						whsAvailableQty = whsAvailableQty - unPickQty;
					}
					// 仓库预配数量 > 仓库的可用数量
					whsPreAlocQty = item.getQty().intValue();
					if (whsPreAlocQty > whsAvailableQty) {
						throw new Exception("可用库存不足！");
					}

					// 拆分
					GdnDtl gdnDtlWhs = new GdnDtl();
					BeanUtil.copyNonNull(gdnDtl, gdnDtlWhs);
					if(ctnrLoading != null) {
			        	gdnDtlWhs.setArrangeCtnrFlag(GdnDtlArrangeCtnrFlagEnum.YES.code);
			        } else {
			        	gdnDtlWhs.setArrangeCtnrFlag(GdnDtlArrangeCtnrFlagEnum.NO.code);
			        }
					gdnDtlWhs.setWhsId(item.getWhsId());
					gdnDtlWhs.setUdf1(GdnDtlUdf1Enum.YES.code);
					gdnDtlWhs.setUdf2(AUTO_TEXT);
					gdnDtlWhs.setOrderQty(new BigDecimal(whsPreAlocQty));
					gdnDtlWhs.setPreAlocQty(new BigDecimal(whsPreAlocQty));
					if (++i == 1) { // 更新原单
						gdnDtlWhs.setModifyUser(loginName);
						gdnDtlWhs.setModifyTime(date);
						gdnDtlMapper.updateById(gdnDtlWhs);
						log.info("【自动分库更新原单】：" + gdnDtlWhs.getGdnDtlId());
					} else { // 拆分新单
						gdnDtlWhs.setGdnDtlId(null);
						gdnDtlWhs.setModifyUser(null);
				        gdnDtlWhs.setModifyTime(null);
						gdnDtlWhs.setCreateTime(date);
						gdnDtlWhs.setCreateUser(loginName);
						gdnDtlWhs.setGdnLineNo(++lockMaxGdnLineNo);
						gdnDtlMapper.insert(gdnDtlWhs);
						log.info("【自动分库拆分新单】：" + gdnDtlWhs.getGdnDtlId());
					}


					// 新增排柜单信息
					if (ctnrLoading != null) {
						ctnrLoading.setCtnrLoadingId(null);
						ctnrLoading.setPlanQty(gdnDtlWhs.getOrderQty());
						ctnrLoading.setGdnDtlId(gdnDtlWhs.getGdnDtlId());
						ctnrLoading.setGdnLineNo(gdnDtlWhs.getGdnLineNo());
						ctnrLoadingMapper.insert(ctnrLoading);
					}

					// 分到每个库区
					for (AvailableInvZoneByWhsResponse invZone : availableInvZone) {
						// 剩余的仓库预配数量等于0时结束库区分配，进入下一下仓库分配，或者分库结束
						if (whsPreAlocQty == 0) {
							break;
						}

						zoneAvailableQty = invZone.getAvailableQty().intValue();
						if (whsPreAlocQty < zoneAvailableQty) {
							// 剩余的仓库预配数量 < 库区的可用数量，【库区预配数量 = 剩余的仓库预配数量】
							zonePreAlocQty = whsPreAlocQty;
						} else {
							// 剩余的仓库预配数量 >= 库区的可用数量，【库区预配数量 = 库区的可用数量】
							zonePreAlocQty = zoneAvailableQty;
						}
						// 剩余的仓库预配数量
						whsPreAlocQty = (whsPreAlocQty - zonePreAlocQty);

						gdnService.confirmInvZone(lotnoStr, gdnDtlWhs, gdnHeader, invZone.getInvZoneId(),
								new BigDecimal(zonePreAlocQty), loginName, date);
					}
				}
			} catch (Exception e) {
				throw e;
			} finally {
				GdnHeader splitHeader = gdnHeaderMapper.selectOne(new QueryWrapper<GdnHeader>().eq("GDN_HEADER_ID", gdnDtl.getGdnHeaderId()));
				if (splitHeader.getSplitDate()==null){
					gdnHeaderMapper.updateGdnSpliDate(splitHeader.getGdnNo());
				}
				log.info(taskName + "锁释放：" + lockKeyStr);
				redisService.unlock(lockKeyStr);
			}
		}
	}
	
	/**
	 * 发货单自动分配仓库--下发拣货
	 * @throws Exception 
	 * @throws  
	 */
	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
	public void createPiacktaskDeal(Long gdnHeaderId, String loginName) throws Exception {
		picktaskService.createPiacktaskJobFromGdn(gdnHeaderId, loginName);
	}
}